#include <Wire.h>
#include <Keypad.h>    // 引用Keypad程式庫
#include <MFRC522.h>
#include <SPI.h>

#define KEY_ROWS 4 // 按鍵模組的列數
#define KEY_COLS 4 // 按鍵模組的行數

// 依照行、列排列的按鍵字元（二維陣列）
char keymap[KEY_ROWS][KEY_COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};


byte colPins[KEY_COLS] = {A0,A1,A2,A3};     // 按鍵模組，行1~4接腳。
byte rowPins[KEY_ROWS] = {7,6,5,4}; // 按鍵模組，列1~4接腳。 
// 初始化Keypad物件
// 語法：Keypad(makeKeymap(按鍵字元的二維陣列), 模組列接腳, 模組行接腳, 模組列數, 模組行數)
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, KEY_ROWS, KEY_COLS);

//rc522 init
#define RST_PIN         2           // Configurable, see typical pin layout above
#define SS_PIN          3          // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.
MFRC522::MIFARE_Key key;

char KEY[8] = {'N','0','0','0','0','0','0','\0'}; 
String MONEY;
char CODE = 'N'; // A/D:增加、减少卡里的现金  ， Y：余额查询 ,B:绑卡

void setup() {
  // put your setup code here, to run once:
  Wire.begin(8);                /* join i2c bus with address 8 */
  Wire.onReceive(receiveEvent); /* register receive event */
  Wire.onRequest(requestEvent); /* register request event */
  Serial.begin(9600);           /* start serial for debug */
  
  while (!Serial);    // 如果串口没有打开，则死循环下去不进行下面的操作
  SPI.begin();        // SPI开始
  mfrc522.PCD_Init(); // Init MFRC522 card
  for (byte i = 0; i < 6; i++) {
        key.keyByte[i] = 0xFF;
  }

  
}

void loop() {
  // put your main code here, to run repeatedly:
  char Key = myKeypad.getKey();   
  if (Key){  // 若有按鍵被按下…
    Serial.println(Key);
    KEY[0] = Key;
    return;
  } 
  if(CODE != 'N'){
    
    CardChange();
    
    
  }

}
//--------------------------------Functions-----------------------------------------------------------------------

//从master接收数据
void receiveEvent(int howMany) { 
  while (0 <Wire.available()) {
    char c = Wire.read();      /* receive byte as a character */
    if((c == 'A' || c == 'D')){ // 如果遇到

      CODE = c;
      int i =0;
      char money[10];
      while (0 <Wire.available()) {
        char m = Wire.read();      /* receive byte as a character */
        if(m == 'E'){
          money[i]='\0';
          MONEY = money;
          Serial.print("CHANGE CODE: ");Serial.println(CODE); 
          Serial.print("CHANGE MONEY: ");Serial.println(MONEY); 
          return;
        }
        money[i] = m;
        i++;
      }
    }
    if(c == 'Y' || c == 'B'){
      CODE = c;
      Serial.print("CHANGE CODE: ");Serial.println(CODE);
    }
  }
}

// 发送数据到master
void requestEvent() { 
  if(KEY[0] != 'N'){  
    Serial.print("send to master: ");Serial.println(KEY);
    Wire.write(KEY,8);   
    KEY[0] = 'N';   
  }
  
}

void dump_byte_array(byte *buffer, byte bufferSize) { 
  for (byte i = 0; i < bufferSize; i++) {
      Serial.print(buffer[i] < 0x10 ? " 0" : " ");
      Serial.print(buffer[i]);
  }
}

//------------------------------------------------------------------------------------------


void CardChange(){ 
  if ( ! mfrc522.PICC_IsNewCardPresent())
        return;

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())
      return;
  
  Serial.print(F("卡片 UID:"));
    dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  Serial.println();
  if(CODE == 'B'){
    KEY[0] = 'Y';
    int i = mfrc522.uid.uidByte[0]+mfrc522.uid.uidByte[1]+mfrc522.uid.uidByte[2]+mfrc522.uid.uidByte[3]+mfrc522.uid.uidByte[4]+mfrc522.uid.uidByte[5];
    String s = (String)i;
    KEY[1] = s[0];
    KEY[2] = s[1];
    KEY[3] = s[2];
    Serial.println(s);
    return;
  }
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  if (    piccType != MFRC522::PICC_TYPE_MIFARE_MINI
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_1K
        &&  piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
        Serial.println(F("This sample only works with MIFARE Classic cards."));
        return;
  }
  
  byte sector         = 14;
  byte blockAddr      = 57;
  
  byte INTEGER= 0x00;
  byte FRACTION = 0x00; 

  byte trailerBlock   = 59;
  MFRC522::StatusCode status;
  byte buffer[18];
  byte size = sizeof(buffer);

  // Authenticate using key A
  Serial.println(F("Authenticating using key A..."));
  status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
      Serial.print(F("PCD_Authenticate() failed: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
      return;
  }
  
  // Read data from the block
  Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
  Serial.println(F(" ..."));
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
  if (status != MFRC522::STATUS_OK) {
      Serial.print(F("MIFARE_Read() failed: "));
      Serial.println(mfrc522.GetStatusCodeName(status));
  }
  Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
  dump_byte_array(buffer, 16); Serial.println();
  Serial.println();
  INTEGER = buffer[0];
  FRACTION = buffer[1];
  int zhengshu = ByteToInt(buffer[0]);
  int fengshu = ByteToInt(buffer[1]);
  float yue = zhengshu + (fengshu *0.01);
  String s_yue = 'Y'+(String)yue; 
  int i;
  for(i =0;i<s_yue.length();i++){
    KEY[i] = s_yue[i];
  }
  KEY[i++]='\0';
  Serial.print("CardHasMoney: "); Serial.println(yue);
  Serial.print("card CODE: ");Serial.println(KEY); 

//-------------------------下方为增加减少卡里的钱函数部分----------------------------------------------
  if(CODE !='Y'){
    byte* data = ChangeMoney(INTEGER,FRACTION);
    
    INTEGER = data[0];
    FRACTION = data[1];
    Serial.print("修改后，卡里有："); Serial.print(INTEGER);Serial.print('.');Serial.println(FRACTION);
    byte dataBlock[] = {
      INTEGER, FRACTION, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 
      0x00, 0x00, 0x00, 0x00, 
      0x00, 0x00, 0x00, 0x00 
    };
//  if(buffer[0]==0xaa && buffer[1]==0xbb && buffer[2]==0xcc && buffer[3]==0xdd){
//    Serial.println("CARD ON!!!!!!!!!!!!!!!!!!!!!!!!!!!");
//  }

    // Authenticate using key B
    Serial.println(F("Authenticating again using key B..."));
    status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
    if (status != MFRC522::STATUS_OK) {
        Serial.print(F("PCD_Authenticate() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
    }
  
    // Write data to the block
    Serial.print(F("Writing data into block ")); Serial.print(blockAddr);
    Serial.println(F(" ..."));
    dump_byte_array(dataBlock, 16); Serial.println();
    status = (MFRC522::StatusCode) mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);
    if (status != MFRC522::STATUS_OK) {
        Serial.print(F("MIFARE_Write() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
    }
    Serial.println();
  
    // Read data from the block (again, should now be what we have written)
    Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
    Serial.println(F(" ..."));
    status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
    if (status != MFRC522::STATUS_OK) {
        Serial.print(F("MIFARE_Read() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
    }
    Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
    dump_byte_array(buffer, 16); Serial.println();
  
    // Check that data in block is what we have written
    // by counting the number of bytes that are equal
    Serial.println(F("Checking result..."));
    byte count = 0;
    for (byte i = 0; i < 16; i++) {
        // Compare buffer (= what we've read) with dataBlock (= what we've written)
        if (buffer[i] == dataBlock[i])
            count++;
    }
    INTEGER = buffer[0];
    FRACTION = buffer[1];
    int zhengshu = ByteToInt(buffer[0]);
    int fengshu = ByteToInt(buffer[1]);
    float yue = zhengshu + (fengshu *0.01);
    String s_yue = 'Y'+(String)yue; 
    int i;
    for(i =0;i<s_yue.length();i++){
      KEY[i] = s_yue[i];
    }
    KEY[i++]='\0';
    Serial.print("CardHasMoney: "); Serial.println(yue);
    Serial.print("card CODE: ");Serial.println(KEY); 
    
  }
  
  CODE = 'N';
  mfrc522.PICC_HaltA();
  // Stop encryption on PCD
  mfrc522.PCD_StopCrypto1();  
}

byte* ChangeMoney(byte INTEGER, byte FRACTION ){
  //卡里的余额
  float card_money = (unsigned int)INTEGER + ((unsigned int)FRACTION *0.01);
  
  const char* c = MONEY.c_str();
  float operation_money = atof(c); //需要进行加减操作的金额
  
  if(CODE == 'A'){
    card_money += operation_money;
  }
  else if(CODE == 'D'){
    card_money -= operation_money;
    
  }
  Serial.println(card_money);
  int integer = card_money;
  int fraction = (int)(card_money*100) % 100;
  byte final_num[2];
  final_num[0] = (byte)card_money;
  final_num[1] = (byte)fraction; 
  Serial.print(final_num[0]);Serial.println(final_num[1]);
  static byte* data = final_num;
  return data;
}

int ByteToInt(byte data){
  int c = (unsigned int)data;
  return c;
  
}
